
import math

class FailrateCalc:
    
    def __init__(self,NStructPerDie,NDiePerWafer,Confidence,OverDispersion):
        self.normsinvdict = {90:1.64485, 95:1.95996}
        self.NStructPerDie = NStructPerDie
        self.NDiePerWafer = NDiePerWafer
        self.Confidence = Confidence
        self.OverDispersion = OverDispersion
        self.normsinvConfidence = self.normsinvdict[Confidence]
        
    
    
    def cround(self,x):
        
        if x < 10.0:
            return round(x,3)
        else:
            return round(x)
        
    def computeD0(self,NFails,ACP,NWafers,NPass=None):
        #print "Yield calc:",NFails,NPass,ACP,NWafers 
        if float(ACP) == 0.0:
            print "Warning: ACP is Zero... please check input data!!!!!!!!"
            return (None,NFails,None)
        
        nfb = NFails
#        if NFails == 0:
#            NFails = 0.5

        try:
            if NPass==None:
                NPass = self.NDiePerWafer * NWafers * 1.00
            else:
                NPass = NPass * 1.00
            
            NFails = NFails * 1.00
        
                
            yld = ((NPass - NFails))/(NPass)
            if yld == 0.0:
                return (None,NFails,None)
            #D0=yld
            D0 = -1.00* math.log(yld) / ACP
            #print D0,yld, -1.00*math.log(yld)
            #print -.5
            
            if yld==1.0:
                D0UpperBound = D0
                D0LowerBound=D0
            else:
                D0LowerBound = math.exp(math.log(D0)-self.normsinvConfidence*math.sqrt(self.OverDispersion*(1-yld)/(NPass*yld*(math.log(yld))**2)))
                D0UpperBound = math.exp(math.log(D0)+self.normsinvConfidence*math.sqrt(self.OverDispersion*(1-yld)/(NPass*yld*(math.log(yld))**2)))
                
        except:
            print "Compute D0 Error. NFails:",NFails," ACP:",ACP
            raise
        
        #if nfb == 0:
        #    D0 = 0.0
        
        
        #D0LowerBound = 0
        #D0UpperBound = 0
        
        return (self.cround(D0UpperBound),self.cround(D0),self.cround(D0LowerBound))
        pass
    pass